/*
File:		ParticleManager.cpp
Author:		Skyler Suzuki
Purpose:	CParticleManager class handles all loaded particle effects 
			and active effects that need to updated to the screen
*/

#include "ParticleManager.h"
#include "Particle.h"
#include "../../TinyXML/tinyxml.h"
#include "../../SGD_Wrappers/CSGD_TextureManager.h"
#include "Emitter.h"
#include <xutility>
#include <cassert>


// Singleton
/*static*/ CParticleManager* CParticleManager::s_pInstance = nullptr;

/*static*/ CParticleManager* CParticleManager::GetInstance()
{
	if( s_pInstance == nullptr )
		s_pInstance = new CParticleManager;

	return s_pInstance;
}

/*static*/ void CParticleManager::DeleteInstance()
{
	delete s_pInstance;
	s_pInstance = nullptr;
}

CParticleManager::CParticleManager(void)
{
	m_bIterating = false;
}


CParticleManager::~CParticleManager(void)
{
	for( vector<CEmitter*>::iterator it = m_vActiveEffects.begin(); it != m_vActiveEffects.end(); ++it)
	{
		delete (*it);
	}
	m_vActiveEffects.clear();
}

bool CParticleManager::LoadParticle(const char *szFileName)
{
	TiXmlDocument doc;
	int sheet = 1;

	if( doc.LoadFile( szFileName ) == false )
		return false;
	TiXmlElement *pRoot = doc.RootElement();

	if( pRoot == nullptr )
		return false;

	m_mapLoadedEffects.clear();

	TiXmlElement *pFile = pRoot->FirstChildElement("FileName");
	
	while( pFile != nullptr )
	{
		CEmitter emitterInfo;

		std::string fileName;
		if(pFile->Attribute("file") != nullptr)
		{
			fileName = pFile->Attribute("file");
			emitterInfo.SetFileName(fileName);
		}

		pFile = pFile->NextSiblingElement("Particles");

		TiXmlElement *pEmitter = pFile->FirstChildElement("Emitter");
		
		std::string isLooping;
		if(pEmitter->Attribute("IsLooping") != nullptr)
		{
			isLooping = pEmitter->Attribute("IsLooping");
			if(isLooping == "false")
			{
				emitterInfo.SetIsLooping(false);
			}
			else
			{
				emitterInfo.SetIsLooping(true);
			}
		}

		std::string Name;
		if(pEmitter->Attribute("Name") != nullptr)
		{
			Name = pEmitter->Attribute("Name");
			emitterInfo.SetParticleName(Name);
		}

		std::string emitShape;
		if(pEmitter->Attribute("emitShape") != nullptr)
		{
			emitShape = pEmitter->Attribute("emitShape");
		}

		TiXmlElement *pEStats = pEmitter->FirstChildElement("Velocity");
		double vEndX;
		pEStats->Attribute("vEndX", &vEndX);
		emitterInfo.SetVelocityEndX((float)vEndX);

		double vStartX;
		pEStats->Attribute("vStartX", &vStartX);
		emitterInfo.SetVelocityStartX((float)vStartX);

		double vEndY;
		pEStats->Attribute("vEndY", &vEndY);
		emitterInfo.SetVelocityEndY((float)vEndY);

		double vStartY;
		pEStats->Attribute("vStartY", &vStartY);
		emitterInfo.SetVelocityStartY((float)vStartY);

		pEStats = pEStats->NextSiblingElement("Scale");
		double sEnd;
		pEStats->Attribute("sEnd", &sEnd);
		emitterInfo.SetScaleEnd((float)sEnd);

		double sStart;
		pEStats->Attribute("sStart", &sStart);
		emitterInfo.SetScaleStart((float)sStart);

		particleColor colorEndLoad, colorStartLoad;
		pEStats = pEStats->NextSiblingElement("Color");
		double cEndA;
		pEStats->Attribute("cEndA", &cEndA);
		colorEndLoad.pCA = (int)cEndA;

		double cEndR;
		pEStats->Attribute("cEndR", &cEndR);
		colorEndLoad.pCR = (int)cEndR;

		double cEndG;
		pEStats->Attribute("cEndG", &cEndG);
		colorEndLoad.pCG = (int)cEndG;

		double cEndB;
		pEStats->Attribute("cEndB", &cEndB);
		colorEndLoad.pCB = (int)cEndB;

		emitterInfo.SetEndColor(colorEndLoad);

		double cStartA;
		pEStats->Attribute("cStartA", &cStartA);
		colorStartLoad.pCA = (int)cStartA;
		double cStartR;
		pEStats->Attribute("cStartR", &cStartR);
		colorStartLoad.pCR = (int)cStartR;
		double cStartG;
		pEStats->Attribute("cStartG", &cStartG);
		colorStartLoad.pCG = (int)cStartG;
		double cStartB;
		pEStats->Attribute("cStartB", &cStartB);
		colorStartLoad.pCB = (int)cStartB;

		emitterInfo.SetStartColor(colorStartLoad);
		
		pEStats = pEStats->NextSiblingElement("Emission");
		double emissionRate;
		pEStats->Attribute("emissionRate", &emissionRate);
		emitterInfo.SetEmissionRate((float)emissionRate);

		pEStats = pEStats->NextSiblingElement("Rotation");
		double rotateEnd;
		pEStats->Attribute("rotateEnd", &rotateEnd);
		emitterInfo.SetRotationEnd((float)rotateEnd);

		double rotateStart;
		pEStats->Attribute("rotateStart", &rotateStart);
		emitterInfo.SetRotationStart((float)rotateStart);

		pEStats = pEStats->NextSiblingElement("Lifetime");
		int maxLife;
		pEStats->Attribute("maxLife", &maxLife);
		emitterInfo.SetMaxLife(maxLife);

		int minLife;
		pEStats->Attribute("minLife", &minLife);
		emitterInfo.SetMinLife(minLife);

		pEStats = pEStats->NextSiblingElement("Shape");
		int nShape;
		pEStats->Attribute("nShape", &nShape);
		emitterInfo.SetEmitterShape((EmitterShape)nShape);
		emitterInfo.SetShape(nShape);

		pEStats = pEStats->NextSiblingElement("MaxParticles");
		int nMaxParticles;
		pEStats->Attribute("nMaxParticles", &nMaxParticles);
		emitterInfo.SetMaxParticles(nMaxParticles);

		CSGD_TextureManager* pTM = CSGD_TextureManager::GetInstance();
		std::string nImageID = "resource/graphics/particles/";
		nImageID = nImageID + fileName;
		TCHAR* param = new TCHAR[nImageID.size()+1];
		param[nImageID.size()] = 0;
		std::copy(nImageID.begin(), nImageID.end(), param);
		emitterInfo.SetImageID(pTM->LoadTexture(param));

		m_mapLoadedEffects.insert(std::pair<std::string, CEmitter>(Name, emitterInfo));

		pFile = pFile->NextSiblingElement("FileName");
		delete param;
	}
	
	return true;
}

void CParticleManager::ActivateEmitter( std::string pName )
{
	assert( m_bIterating == false && "CParticleManager::ActivateEmitter - cannot add while iterating" );
	CEmitter* pushedEmit = new CEmitter(m_mapLoadedEffects[pName]);
	m_vActiveEffects.push_back(pushedEmit);
	//m_mapLoadedEffects[pName].AddRef();
}

void CParticleManager::RemoveEmitter( CEmitter* cEmit )
{
	//assert( m_bIterating == false && "CParticleManager::RemoveEmitter - cannot remove while iterating" );
	
	//for( vector<CEmitter>::iterator it = m_vActiveEffects.begin(); it != m_vActiveEffects.end(); ++it)
	//{
	//	if( &(*it) == &cEmit )	
	//	{
	//		m_vActiveEffects.erase(it);
	//		break;
	//	}
	//}

	for( vector<CEmitter*>::iterator it = m_vActiveEffects.begin(); it != m_vActiveEffects.end(); ++it)
	{
		if( (*it) == cEmit )	
		{
			delete(*it);
			m_vActiveEffects.erase(it);
			break;
		}
	}
}


void CParticleManager::UpdateActiveEmitter(float fElapsedTime)
{
	//m_bIterating = true;

	for( vector<CEmitter*>::iterator it = m_vActiveEffects.begin(); it != m_vActiveEffects.end(); ++it)
	{
		if(!(*it)->Update(fElapsedTime))
		{
			RemoveEmitter((*it));
			break;
		}
	}

	//m_bIterating = false;
}

void CParticleManager::RenderAll()
{
	//m_bIterating = true;

	for( vector<CEmitter*>::iterator it = m_vActiveEffects.begin(); it != m_vActiveEffects.end(); ++it)
	{
		(*it)->Render();		
	}

	//m_bIterating = false;
}
